#include <stdio.h>

/* ©2012 Harry Broeders 
   Uitwerking van opgave 8 van paragraaf 6.18 uit het boek "De programmeertaal C", 4de editie van Kelley en Pohl */

/* In theorie is het aantal optellingen bij de naieve methode gelijk aan de graad van de polynoom (n).
   Het aatal vermenigvuldigingen bij de naieve methode is gelijk aan de som van i = 0 t/m n (n = de graad
   van de polynoom). Deze reeks is gelijk aan 0.5*n*(n+1). Voor een 4de graads polynoom is het aantal 
   vermenigvuldigingen dus 0.5*4*5 = 10. */

double eval(double p[], double x, int n) {
    int i, j;
    double res = p[0];
    int aantalOptellingen = 0, aantalVermenigvuldigingen = 0;
    for (i = 1 ; i <= n; i = i + 1) {
        /* bereken x^i */
        double xTotDeMachti = x;
        for (j = 1; j < i; j = j + 1) {
            xTotDeMachti = xTotDeMachti * x;
            aantalVermenigvuldigingen = aantalVermenigvuldigingen + 1;
        }
        res = res + p[i] * xTotDeMachti;
        aantalOptellingen = aantalOptellingen + 1;
        aantalVermenigvuldigingen = aantalVermenigvuldigingen + 1;
    }
    printf("graad = %d : aantalOptellingen = %d, aantalVermenigvuldigingen = %d\n", n, aantalOptellingen, aantalVermenigvuldigingen);
    return res;
}

/* In theorie is het aantal optellingen bij de methode van Horner gelijk aan de graad van de polynoom (n).
   Het aatal vermenigvuldigingen bij de methode van Horner is ook gelijk aan de graad van de polynoom (n).
   Voor een 4de graads polynoom is het aantal vermenigvuldigingen dus 4. */

double evalHorner(double p[], double x, int n) {
    int i;
    double res = p[n];
    int aantalOptellingen = 0, aantalVermenigvuldigingen = 0;
    for (i = n - 1; i >= 0; i = i - 1) {
        res = p[i] + x * res;
        aantalOptellingen = aantalOptellingen + 1;
        aantalVermenigvuldigingen = aantalVermenigvuldigingen + 1;
    }
    printf("graad = %d : aantalOptellingen = %d, aantalVermenigvuldigingen = %d\n", n, aantalOptellingen, aantalVermenigvuldigingen);
    return res;
}

void printErrorAlsOngelijk(double x, double y) {
    /* if (x != y) werkt niet vanwege afrondingsfouten ! */
    double verschil = x - y;
    double absoluutVerschil; 
    if (verschil > 0) {
        absoluutVerschil = verschil;
    }
    else {
        absoluutVerschil = -verschil;
    }
    if (absoluutVerschil >= 1E-10) {
        printf("Error: verwachte waarde = %.10f maar werkelijke waarde is %.10f\n", y, x);
    }
}

int main(void) {
    double p0[] = {-3};                     /* f(x) = -3                                         */
    double p1[] = {4, -4};                  /* f(x) =  4 +   -4*x                                */
    double p2[] = {-2, -1, 1};              /* f(x) = -2 +   -1*x +    1*x^2                     */
    double p3[] = {-2, -1.5, 0.75, 0.25};   /* f(x) = -2 + -1.5*x + 0.75*x^2 +  0.25*x^3         */
    double p4[] = {3, 0.3, -0.5, 6.125, 2}; /* f(x) =  3 +  0.3*x + -0.5*x^2 + 6.125*x^3 + 2*x^4 */
    double y;

    printf("Naief\n");

    y = eval(p0, 3.2, 0); printErrorAlsOngelijk(y, -3);
    y = eval(p1, 3.2, 1); printErrorAlsOngelijk(y, -8.8);
    y = eval(p2, 3.2, 2); printErrorAlsOngelijk(y, 5.04);
    y = eval(p3, 3.2, 3); printErrorAlsOngelijk(y, 9.072);
    y = eval(p4, 3.2, 4); printErrorAlsOngelijk(y, 409.2592);

    printf("Horner\n");

    y = evalHorner(p0, 3.2, 0); printErrorAlsOngelijk(y, -3);
    y = evalHorner(p1, 3.2, 1); printErrorAlsOngelijk(y, -8.8);
    y = evalHorner(p2, 3.2, 2); printErrorAlsOngelijk(y, 5.04);
    y = evalHorner(p3, 3.2, 3); printErrorAlsOngelijk(y, 9.072);
    y = evalHorner(p4, 3.2, 4); printErrorAlsOngelijk(y, 409.2592);

    fflush(stdin);
    getchar();
    return 0;
}